Skip to content
掌握度

对比小林《事务隔离级别是怎么实现的》《可重复读完全解决幻读了吗》、JavaGuide InnoDB 对 MVCC 的实现、二哥《浅入深出 MySQL 事务的实现》与面渣逆袭《MySQL 事务》(侧边栏进入)。

多版对比 ​

ACID 的实现归因,有一处必须纠偏​:小林的口径准确——redo log 保持久性、undo log 保原子性、MVCC + 锁保隔离性、一致性由前三者共同保证​;面渣把「一致性归 undo、原子性和持久性归 redo」说反了,属笔误,题解采小林口径。二哥补了维度更高的通识:并发控制有锁、时间戳、MVCC+快照隔离三种机制,MySQL 选了最后一种;并辨析 ACID 的一致性和 CAP 的一致性不是一回事。

MVCC 机制,JG 最严谨​:隐藏字段(TRX_ID/ROLL_PTR/ROW_ID)、undo log 版本链、ReadView 四要素(m_ids、min、max、creator)——JG 给到 C 源码结构和完整可见性算法(含二分查找);小林用版本链逐步推演可见性判断,故事线更好讲。​RC 和 RR 的唯一区别:RC 每条 select 新建 ReadView,RR 整个事务共用第一个——两家用同一口径。

幻读,小林的「没完全解决」论证独有​:快照读靠 MVCC 防幻读、当前读靠 next-key lock 防幻读,但他给出两个反例证明可重复读下幻读仍可能出现(先快照读后当前读的错序场景),所以才有「完全解决」的争议表述。

最优题解 ​

事务四特性的实现各有归属:原子性靠 undo log(失败回滚到版本链),持久性靠 redo log(WAL,先写日志再刷数据页),隔离性靠 MVCC 加锁,一致性是前三个共同达成的结果。隔离级别解决读问题:读未提交什么都不防,读已提交和可重复读靠 MVCC,串行化直接加锁。

MVCC 的核心是版本链加 ReadView:每行有隐藏的事务 ID 和回滚指针,改动串成 undo 版本链;读的时候生成 ReadView(活跃事务列表、最小最大事务 ID、创建者),沿着版本链找第一个对「我」可见的版本。RC 和 RR 只差一步——RC 每条查询新建 ReadView,所以能读到别人已提交的新数据;RR 整个事务用第一次的 ReadView,所以可重复。可重复读对幻读是「基本防住」:快照读靠 MVCC、当前读靠 next-key lock,但先快照读再当前读的混用场景仍可能看到幻影行,这是 Innodb 的已知边界。

追问链 ​

追问:为什么 RR 是默认级别而不是 RC?​ 参考答:历史与主从相关——RC 下 binlog 需要 ROW 格式才能保证语句安全(STATEMENT 格式在 RC 下会导致主从不一致),早期 ROW 开销大所以默认 RR;现在 binlog 默认 ROW,很多大厂在线上其实改用 RC。

追问:next-key lock 锁的是什么?​ 参考答:记录锁加间隙锁的组合,锁住记录及其前面的间隙——当前读(select for update / update)时防止别的事务在范围内插入新行,这就是当前读防幻读的机制。

我的理解 ​

这题先纠错再答题:面渣的 ACID 归因是错的(undo 管原子性、redo 管持久性),面试里照背会被追问打穿。层次感来自三步:版本链 + ReadView 的机制(JG 最细)→ RC/RR 只差 ReadView 生成时机(两方共识)→ 小林的「RR 没完全解决幻读」反例。二哥的「三种并发控制机制」和「ACID vs CAP」是展示视野的加分句。

本站仅供个人学习使用,请勿外传